package com.xbongbong.workflow.service.operator.impl;

import com.alibaba.fastjson.JSONObject;
import com.xbongbong.formula.service.FunctionService;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.pojo.workflow.WorkflowDataPojo;
import com.xbongbong.paas.pojo.workflow.WorkflowExplainPojo;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.PaasStringUtil;
import com.xbongbong.paas.toolbox.util.RegexUtil;
import com.xbongbong.paas.util.WorkflowUtil;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.workflow.WorkflowValueTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.workflow.domain.entity.WorkflowNodeEntity;
import com.xbongbong.workflow.pojo.Data;
import com.xbongbong.workflow.pojo.FlowData;
import com.xbongbong.workflow.pojo.FlowDatas;
import com.xbongbong.workflow.pojo.WorkflowOperationsPojo;
import com.xbongbong.workflow.pojo.WorkflowTransferPOJO;
import com.xbongbong.workflow.service.operator.WorkflowOperatorFieldHandler;
import com.xbongbong.workflow.service.operator.WorkflowOperatorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author 吴峰
 * @date 2021/06/18 15:09
 */
@Service("workflowFormulaOperatorServiceImpl")
public class WorkflowFormulaOperatorServiceImpl implements WorkflowOperatorService {

    private static final Logger LOGGER = LoggerFactory.getLogger(WorkflowFormulaOperatorServiceImpl.class);

    @Resource
    private Map<Integer, WorkflowOperatorFieldHandler> workflowOperatorFieldMap;
    @Resource
    private FunctionService functionService;


    @Override
    public Integer type() {
        return WorkflowValueTypeEnum.FORMULA.getType();
    }

    @Override
    public Object operatorByInsertNodeSourceData(WorkflowNodeEntity workflowNodeEntity,  FieldAttrEntity fieldAttrEntity, FieldAttrEntity targetField, Map<Long, PaasFormDataEntityExt> formDataMap,
                           Map<Long, JSONObject> dataMap, WorkflowOperationsPojo workflowOperationsPojo, WorkflowDataPojo workflowDataPojo,
                                                 WorkflowTransferPOJO workflowTransferPojo, WorkflowExplainPojo workflowExplainPojo) throws XbbException {

        try {
            String corpid = workflowNodeEntity.getCorpid();
            FlowDatas flowDatas = workflowTransferPojo.getFlowDatas();
            flowDatas = flowDatas ==null ? new FlowDatas() : workflowTransferPojo.getFlowDatas();
            Map<String, FlowData> flowDataMap = flowDatas.getNodeIdMap();
            flowDataMap = flowDataMap == null ? new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY) : flowDataMap;
            Data workflowData = workflowTransferPojo.getData();
            String formula = workflowOperationsPojo.getFormulaInfo().getFormula();
            String[] formulaList = RegexUtil.getFormulaAttr(formula);
            // 遍历公式
            for (int i = 0; i < formulaList.length; i++) {
                Object value = null;
                String formulaStr = formulaList[i];
                // 获取公式的单个字段级别
                String[] list = WorkflowUtil.getAttrByFormula(formulaStr);
                if (formulaStr.contains(FieldTypeEnum.SUB_FORM.getEsalias())) {
                    // 含子表单的字段处理
                    String flag = list[0];
                    Long workflowNodeId = Long.valueOf(list[1]);
                    Integer triggerNodeFlag = Integer.valueOf(flag);
                    JSONObject data = dataMap.get(workflowNodeId);
                    PaasFormDataEntity paasFormDataEntity = formDataMap.get(workflowNodeId);
                    Long formId;
                    Integer businessType;
                    if (Objects.equals(1, triggerNodeFlag)) {
                        formId = workflowData.getFormId();
                        businessType = workflowData.getBusinessType();
                    } else {
                        FlowData flowData = flowDataMap.get(workflowNodeId.toString());
                        formId = flowData.getFormId();
                        businessType = flowData.getBusinessType();
                    }
                    fieldAttrEntity = getSubField(workflowExplainPojo, formulaStr, list[2], list[3], list[4]);
                    WorkflowOperatorFieldHandler workflowOperatorFieldHandler = workflowOperatorFieldMap.get(fieldAttrEntity.getFieldType());
                    value = workflowOperatorFieldHandler.formulaHandlerThisField(fieldAttrEntity, paasFormDataEntity, data, formId,
                            businessType, corpid);
                }  else if (formulaStr.contains("user.")) {
                    value = formulaStr.replace("user.", "").replaceAll("[\\{\\}]", "");
                } else if (formulaStr.contains("dept.")) {
                    value = formulaStr.replace("dept.", "").replaceAll("[\\{\\}]", "");
                }else if (WorkflowUtil.validateFormula(list, formulaStr)){
                    // 不含子表单的字段处理
                    String flag = list[0];
                    Long workflowNodeId = Long.valueOf(list[1]);
                    fieldAttrEntity = getField(workflowDataPojo, formulaStr, list[2], list[3]);
                    Integer triggerNodeFlag = Integer.valueOf(flag);
                    JSONObject data;
                    Long formId;
                    Integer businessType;
                    PaasFormDataEntity paasFormDataEntity = formDataMap.get(workflowNodeId);
                    if (Objects.equals(1, triggerNodeFlag)) {
                        formId = workflowData.getFormId();
                        businessType = workflowData.getBusinessType();
                        data = paasFormDataEntity.getData();
                    } else {
                        FlowData flowData = flowDataMap.get(workflowNodeId.toString());
                        formId = flowData.getFormId();
                        businessType = flowData.getBusinessType();
                        data = paasFormDataEntity.getData();
                    }
                    WorkflowOperatorFieldHandler workflowOperatorFieldHandler = workflowOperatorFieldMap.get(fieldAttrEntity.getFieldType());
                    value = workflowOperatorFieldHandler.formulaHandlerThisField(fieldAttrEntity, paasFormDataEntity, data, formId,
                            businessType, corpid);
                }
                if (Objects.isNull(value)) {
                    formula = null;
                    break;
                }
                // 将公式的单个字段的值，替换掉公式
                formula = formula.replace(formulaList[i], value.toString());
            }
            // 运行公式
            Object value = functionService.expressRun(formula, new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY));
            value = PaasStringUtil.replaceQuotes(value);
            WorkflowOperatorFieldHandler workflowOperatorFieldHandler = workflowOperatorFieldMap.get(targetField.getFieldType());
            // 将值进行转换目标字段的值，如下拉框，下拉多选，复选框，下拉多选进行转换，数字精度的换算等
            value = workflowOperatorFieldHandler.formulaHandlerTargetField(value, workflowOperationsPojo, targetField, workflowNodeEntity, workflowNodeEntity.getCorpid());
            return value;
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOGGER.error("WorkflowFormulaOperatorServiceImpl.operator", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }


    private FieldAttrEntity getField(WorkflowDataPojo workflowDataPojo, String formulaStr, String formIdStr, String attr) {
        FieldAttrEntity fieldAttrEntity;
        if (formulaStr.contains(XbbRefTypeEnum.WORK_ORDER.getAlias())) {
            fieldAttrEntity = workflowDataPojo.getExplainMap().get(formIdStr).get(attr);
        } else {
            fieldAttrEntity = workflowDataPojo.getExplainMap().get(formIdStr).get(attr);
        }
        return fieldAttrEntity;
    }

    private FieldAttrEntity getSubField(WorkflowExplainPojo workflowExplainPojo, String formulaStr, String formIdStr, String attr, String subKey) {
        FieldAttrEntity fieldAttrEntity;
        if (formulaStr.contains(XbbRefTypeEnum.WORK_ORDER.getAlias())) {
            Long formId = Long.valueOf(formIdStr.replace(PaasConstant.WORK_ORDER, ""));
            fieldAttrEntity = workflowExplainPojo.getWorkOrderSubExplainMap().get(formId).get(attr).get(subKey);
        } else {
            Long formId = Long.valueOf(formIdStr);
            fieldAttrEntity = workflowExplainPojo.getSubExplainMap().get(formId).get(attr).get(subKey);
        }
        return fieldAttrEntity;
    }

    @Override
    public Object operatorByUpdateNode(WorkflowNodeEntity workflowNodeEntity, FieldAttrEntity fieldAttrEntity, FieldAttrEntity targetField,
                                       Map<Long, PaasFormDataEntityExt> formDataMap, Map<Long, JSONObject> dataMap, WorkflowOperationsPojo workflowOperationsPojo,
                                       WorkflowDataPojo workflowDataPojo, WorkflowTransferPOJO workflowTransferPojo, WorkflowExplainPojo workflowExplainPojo) throws XbbException {
        try {
            String corpid = workflowNodeEntity.getCorpid();
            FlowDatas flowDatas = workflowTransferPojo.getFlowDatas();
            Map<String, FlowData> flowDataMap = flowDatas.getNodeIdMap();
            String formula = workflowOperationsPojo.getFormulaInfo().getFormula();
            String[] formulaList = RegexUtil.getFormulaAttr(formula);
            for (int i = 0; i < formulaList.length; i++) {
                Object value = null;
                String formulaStr = formulaList[i];
                String[] list = WorkflowUtil.getAttrByFormula(formulaStr);
                if (formulaStr.contains(FieldTypeEnum.SUB_FORM.getEsalias())) {
                    Integer flag = Integer.valueOf(list[0]);
                    Long workflowNodeId = Long.valueOf(list[1]);
                    Long formId;
                    Integer businessType;
                    JSONObject data;
                    if (Objects.equals(1, flag)){
                        formId = workflowTransferPojo.getData().getFormId();
                        businessType = workflowTransferPojo.getData().getBusinessType();
                        data = dataMap.get(workflowNodeId);
                    } else {
                        FlowData flowData = flowDataMap.get(workflowNodeId.toString());
                        formId = flowData.getFormId();
                        businessType = flowData.getBusinessType();
                        data = dataMap.get(workflowNodeId);
                    }

                    PaasFormDataEntity paasFormDataEntity = formDataMap.get(workflowNodeId);
                    fieldAttrEntity = getSubField(workflowExplainPojo, formulaStr, list[2], list[3], list[4]);
                    WorkflowOperatorFieldHandler workflowOperatorFieldHandler = workflowOperatorFieldMap.get(fieldAttrEntity.getFieldType());
                    value = workflowOperatorFieldHandler.formulaHandlerThisField(fieldAttrEntity, paasFormDataEntity, data, formId,
                            businessType, corpid);
                } else if (formulaStr.contains("user.")) {
                    value = formulaStr.replace("user.", "").replaceAll("[\\{\\}]", "");
                } else if (formulaStr.contains("dept.")) {
                    value = formulaStr.replace("dept.", "").replaceAll("[\\{\\}]", "");
                }else if (WorkflowUtil.validateFormula(list, formulaStr)){
                    Long workflowNodeId = Long.valueOf(list[1]);
                    Long formId;
                    Integer businessType;
                    Integer flag = Integer.valueOf(list[0]);
                    JSONObject data;
                    PaasFormDataEntity paasFormDataEntity = formDataMap.get(workflowNodeId) == null ? new PaasFormDataEntity() : formDataMap.get(workflowNodeId);
                    data = paasFormDataEntity.getData() == null ? new JSONObject() : paasFormDataEntity.getData();
                    if (Objects.equals(1, flag)){
                        // 开始节点
                        formId = workflowTransferPojo.getData().getFormId();
                        businessType = workflowTransferPojo.getData().getBusinessType();
                    } else {
                        // 出开始节点外的其他节点，需要根据节点id获取
                        FlowData flowData = flowDataMap.get(workflowNodeId.toString());
                        formId = flowData.getFormId();
                        businessType = flowData.getBusinessType();
                    }
                    fieldAttrEntity = getField(workflowDataPojo, formulaStr, list[2], list[3]);

                    WorkflowOperatorFieldHandler workflowOperatorFieldHandler = workflowOperatorFieldMap.get(fieldAttrEntity.getFieldType());
                    value = workflowOperatorFieldHandler.formulaHandlerThisField(fieldAttrEntity, paasFormDataEntity, data, formId,
                            businessType, corpid);
                }
                if (Objects.isNull(value)) {
                    formula = null;
                    break;
                }
                formula = formula.replace(formulaList[i], value.toString());
            }
            Object value = functionService.expressRun(formula, new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY));
            value = PaasStringUtil.replaceQuotes(value);
            WorkflowOperatorFieldHandler workflowOperatorFieldHandler = workflowOperatorFieldMap.get(targetField.getFieldType());
            value = workflowOperatorFieldHandler.formulaHandlerTargetField(value, workflowOperationsPojo, targetField, workflowNodeEntity, corpid);
            return value;
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOGGER.error("WorkflowFormulaOperatorServiceImpl.operatorByUpdateNode", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }
}
